package com.ebt.m.customer.view;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.text.TextPaint;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import com.ebt.m.R;

/**
 * @author Rick.Wang
 * 用于竖直显示单个字符的view，可以在触摸滑动此view时返回正在按下的字符的索引等
 */
public class VerticalStraightTextView extends View {

    public final static int DEFAULT_INDEX_NOT_PICKED = -1;

    private final static int DEFAULT_TEXT_SIZE = 15;
    private final static int DEFAULT_TEXT_COLOR_NORMAL = 0x99333333;
    private final static int DEFAULT_TEXT_COLOR_PRESSED = 0x99333333;
    private final static int DEFAULT_BACKGROUND_COLOR_NORMAL = 0x00000000;
    private final static int DEFAULT_BACKGROUND_COLOR_PRESSED = 0x00000000;

    private Paint.FontMetrics mFontMetrics;
    private TextPaint mTextPaintNormal;
    private TextPaint mTextPaintPressed;
    private String mText = "";

    private int mTextLength;
    private int mCharWidth;
    private int mCharHeight;

    private int mCurrPickedCharIndex = DEFAULT_INDEX_NOT_PICKED;

    private int mColorBackgroundNormal = DEFAULT_BACKGROUND_COLOR_NORMAL;
    private int mColorBackgroundPressed = DEFAULT_BACKGROUND_COLOR_PRESSED;

    //draw文字时修正baseline与中心点的偏移
    private float mFontDeltaY;
    private float[] mCoordinates;

    //view的size属性
    private int height;
    private int width;
    private int paddingTop;
    private int paddingBottom;
    private int paddingLeft;
    private int paddingRight;

    public VerticalStraightTextView(Context context) {
        this(context, null);
    }

    public VerticalStraightTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initValues();
        initAttrs(context, attrs);
        initFontSize();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        float maxCharWidth = 0f;
        for(int i = 0; i < mTextLength; i++){
            maxCharWidth = Math.max(mTextPaintNormal.measureText(mText.substring(i, i+1)), maxCharWidth);
        }
        mCharWidth = (int)Math.ceil(maxCharWidth);
        Rect textBounds = new Rect();
        mTextPaintNormal.getTextBounds(mText, 0, mTextLength, textBounds);
        mCharHeight = textBounds.height();
        setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        initViewSizeConfig();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawViewBackground(canvas);
        drawViewText(canvas);
    }

    private final void initValues() {
        mTextPaintNormal = new TextPaint();
        mTextPaintNormal.setAntiAlias(true);
        mTextPaintNormal.setTextSize(DEFAULT_TEXT_SIZE);
        mTextPaintNormal.setTextAlign(Paint.Align.CENTER);
        mTextPaintNormal.setColor(DEFAULT_TEXT_COLOR_NORMAL);
        mTextPaintPressed = new TextPaint(mTextPaintNormal);
        mTextPaintPressed.setColor(DEFAULT_TEXT_COLOR_PRESSED);
    }

    private void initAttrs(Context context, AttributeSet attrs){
        if(attrs == null){
            return;
        }
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.VerticalStraightTextView);
        int n = a.getIndexCount();
        for (int i = 0; i < n; i++) {
            int attr = a.getIndex(i);
            switch (attr) {
                case R.styleable.VerticalStraightTextView_vst_text:
                    mText = a.getString(attr);
                    if(mText == null){
                        mText = "";
                        break;
                    }
                    mTextLength = mText.length();
                    break;
                case R.styleable.VerticalStraightTextView_vst_textSize:
                    int textSize = a.getDimensionPixelOffset(attr, DEFAULT_TEXT_SIZE);
                    if (textSize > 0) {
                        mTextPaintNormal.setTextSize(textSize);
                        mTextPaintPressed.setTextSize(textSize);
                        mFontMetrics = mTextPaintNormal.getFontMetrics();
                        mFontDeltaY = Math.abs((mFontMetrics.top + mFontMetrics.bottom)/2);
                    }
                    break;
                case R.styleable.VerticalStraightTextView_vst_textColorNormal:
                    mTextPaintNormal.setColor(a.getColor(attr, DEFAULT_TEXT_COLOR_NORMAL));
                    break;
                case R.styleable.VerticalStraightTextView_vst_textColorPressed:
                    mTextPaintPressed.setColor(a.getColor(attr, DEFAULT_TEXT_COLOR_PRESSED));
                    break;
                case R.styleable.VerticalStraightTextView_vst_backgroundColorNormal:
                    mColorBackgroundNormal = a.getColor(attr, DEFAULT_BACKGROUND_COLOR_NORMAL);
                    break;
                case R.styleable.VerticalStraightTextView_vst_backgroundColorPressed:
                    mColorBackgroundPressed = a.getColor(attr, DEFAULT_BACKGROUND_COLOR_PRESSED);
                    break;
            }
        }
        a.recycle();
    }

    private void initFontSize(){
        mFontMetrics = mTextPaintNormal.getFontMetrics();
        mFontDeltaY = Math.abs((mFontMetrics.top + mFontMetrics.bottom)/2);
    }

    private void initViewSizeConfig(){
        height = getMeasuredHeight();
        width = getMeasuredWidth();
        paddingTop = getPaddingTop();
        paddingBottom = getPaddingBottom();
        paddingLeft = getPaddingLeft();
        paddingRight = getPaddingRight();
    }

    private int measureWidth(int measureSpec) {
        int result = 0;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);

        if (specMode == MeasureSpec.EXACTLY) {
            result = specSize;
        } else {
            result = this.getPaddingLeft() + this.getPaddingRight() + mCharWidth;
            if (specMode == MeasureSpec.AT_MOST) {
                result = Math.min(result, specSize);
            }
        }
        return result;
    }

    private int measureHeight(int measureSpec) {
        int result = 0;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);

        if (specMode == MeasureSpec.EXACTLY) {
            result = specSize;
        } else {
            result = getPaddingTop() + getPaddingBottom();
            if(mTextLength > 0){
                result += mTextLength * mCharHeight;
            }
            if (specMode == MeasureSpec.AT_MOST) {
                result = Math.min(result, specSize);
            }
        }
        return result;
    }

    private void drawViewBackground(Canvas canvas){
        if(mCurrPickedCharIndex == DEFAULT_INDEX_NOT_PICKED){
            canvas.drawColor(mColorBackgroundNormal);
        }else{
            canvas.drawColor(mColorBackgroundPressed);
        }
    }

    private void drawViewText(Canvas canvas){
        if(mTextLength == 0){
            return;
        }
        //单个字符的x点坐标值
        float x = (float)(width + paddingLeft - paddingRight)/2;
        //单个字符的y点坐标值
        float y = 0;

        float cellHeight = (float)(height - paddingTop - paddingBottom) / (float)mTextLength;

        if(mCoordinates == null || mCoordinates.length != mTextLength){
            mCoordinates = new float[mTextLength + 1];
        }
        mCoordinates[0] = 0;
        for(int i = 0; i < mTextLength; i++){
            y = paddingTop + i * cellHeight + cellHeight/2;

            mCoordinates[i + 1] = paddingTop + (i + 1) * cellHeight;

            if(mCurrPickedCharIndex != i){
                canvas.drawText(mText, i, i + 1, x, y + mFontDeltaY, mTextPaintNormal);//确保居中
            }else{
                canvas.drawText(mText, i, i + 1, x, y + mFontDeltaY, mTextPaintPressed);
            }
        }
        mCoordinates[mTextLength] = height;
    }

    public void setText(String text) {
        if(text == null){
            text = "";
        }
        if(!mText.equals(text)){
            mText = text;
            mTextLength = text.length();
            requestLayout();
            invalidate();
        }
    }

    public void setTextSize(int size) {
        if(mTextPaintNormal.getTextSize() != size){
            mTextPaintNormal.setTextSize(size);
            mTextPaintPressed.setTextSize(size);
            requestLayout();
            invalidate();
        }
    }

    public void setTextColor(int color) {
        if(color != mTextPaintNormal.getColor()){
            mTextPaintNormal.setColor(color);
            invalidate();
        }
    }

    public void setTextColorPicked(int color) {
        if(color != mTextPaintPressed.getColor()){
            mTextPaintPressed.setColor(color);
            invalidate();
        }
    }

    /***************************************
     *
     * 		+---------------+  <-- Y == coordinates[0]
     * 		|		#		|
     * 		|---------------|			coordinates[1]
     * 		|		A		|
     * 		|---------------|			coordinates[2]
     * 		|		B		|
     * 		|---------------|			coordinates[3]
     * 		|		C		|
     * 		+---------------|			coordinates[4]
     ***************************************/

    /**
     * y is the coordinate-Y
     * this function can return the "touched char index"
     * @param y
     * @return
     */
    public int getPickedCharIndex(float y){

        if(mCurrPickedCharIndex > DEFAULT_INDEX_NOT_PICKED){
            if(mCoordinates[mCurrPickedCharIndex] < y && y < mCoordinates[mCurrPickedCharIndex +1]){
                return mCurrPickedCharIndex;
            }
        }

        int start = 0;
        int end = mCoordinates.length - 1;
        while (start != end - 1) {
            int middle = (start + end) / 2;
            if (y < mCoordinates[middle]) {
                end = middle;
            } else if (y > mCoordinates[middle]) {
                start = middle;
            }
        }
        return start;
    }

    /**
     * y is the coordinate-Y
     * this function can return the "touched char"
     * @param y
     * @return
     */
    public String getPickedChar(float y){
        if(TextUtils.isEmpty(mText)){
            return null;
        }
        return String.valueOf(mText.charAt(getPickedCharIndex(y)));
    }

    public void setCurrPickedCharIndex(int newPickedCharIndex){
        if(mCurrPickedCharIndex != newPickedCharIndex){
            if(mOnTouchedCharListener != null && !TextUtils.isEmpty(mText)){

                if(DEFAULT_INDEX_NOT_PICKED == newPickedCharIndex){
                    mOnTouchedCharListener.onTouchedCharReleasedFinally(String.valueOf(mText.charAt(mCurrPickedCharIndex)),
                            mCurrPickedCharIndex);
                }else{
                    if(DEFAULT_INDEX_NOT_PICKED != mCurrPickedCharIndex){
                        mOnTouchedCharListener.onTouchedCharReleased(String.valueOf(mText.charAt(mCurrPickedCharIndex)),
                                mCurrPickedCharIndex);

                        mOnTouchedCharListener.onTouchedCharChanged(String.valueOf(mText.charAt(mCurrPickedCharIndex)),
                                mCurrPickedCharIndex,
                                String.valueOf(mText.charAt(newPickedCharIndex)),
                                newPickedCharIndex);
                    }
                    mOnTouchedCharListener.onTouchedCharPicked(String.valueOf(mText.charAt(newPickedCharIndex)),
                            newPickedCharIndex);
                }
            }
            mCurrPickedCharIndex = newPickedCharIndex;
            invalidate();
        }
    }

    private OnTouchedCharListener mOnTouchedCharListener;

    public void setOnTouchedCharListener(OnTouchedCharListener onTouchedCharListener){
        mOnTouchedCharListener = onTouchedCharListener;
    }

    public static interface OnTouchedCharListener{
        /**
         * 调用情形：手指抬起
         * @param releasedString 	手指抬起时的String
         * @param releasedIndex		手指抬起时的String索引
         */
        void onTouchedCharReleasedFinally(String releasedString, int releasedIndex);

        /**
         * 调用情形：手指滑动或者手指抬起
         * @param releasedString	手指滑动离开时，或者手指抬起时的String
         * @param releasedIndex		手指滑动离开时，或者手指抬起时的String索引
         */
        void onTouchedCharReleased(String releasedString, int releasedIndex);
        /**
         * 调用情形：手指滑动
         * @param releasedString	手指滑动时离开的String
         * @param releasedIndex		手指滑动时离开的String索引
         * @param pickedString		手指滑动时选中的String
         * @param pickedIndex		手指滑动时选中的String索引
         */
        void onTouchedCharChanged(String releasedString, int releasedIndex, String pickedString, int pickedIndex);
        /**
         * 调用情形：手指按下或者手指滑动
         * @param pickedString		手指按下或者手指滑动时选中的String
         * @param pickedIndex		手指按下或者手指滑动时选中的String索引
         */
        void onTouchedCharPicked(String pickedString, int pickedIndex);//调用情形：手指按下+手指滑动
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_MOVE:
                setCurrPickedCharIndex(getPickedCharIndex(event.getY()));
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                setCurrPickedCharIndex(DEFAULT_INDEX_NOT_PICKED);
                break;
        }
        return true;
    }

}